import 'dart:async';
import 'dart:io';

import 'package:flutter/services.dart';
import 'pedometer_interface.dart';
import 'pedestrian_status.dart';
import 'step_count.dart';
import 'constant.dart';

/// Implementation of screen brightness platform interface
class MethodChannelPedometer extends PedometerPlatform {

  static const EventChannel _stepDetectionChannel =
  const EventChannel('step_detection');
  static const EventChannel _stepCountChannel =
  const EventChannel('step_count');

  static StreamController<PedestrianStatus> _androidPedestrianController =
  StreamController.broadcast();

  /// Returns one step at a time.
  /// Events come every time a step is detected.
  @override
  Stream<PedestrianStatus> get pedestrianStatusStream  {
    Stream<PedestrianStatus> stream = _stepDetectionChannel
        .receiveBroadcastStream()
        .map((event) => PedestrianStatus.fromEvent(event));
    if (Platform.isAndroid) return _androidStream(stream);
    return stream;
  }

  /// Transformed stream for the Android platform
  static Stream<PedestrianStatus> _androidStream(
      Stream<PedestrianStatus> stream) {
    /// Init a timer and a status
    Timer? t;
    int? pedestrianStatus;

    /// Listen for events on the original stream
    /// Transform these events by using the timer
    stream.listen((dynamic e) {
      /// If an event is received it means the status is 'walking'
      /// If the timer has been started, it should be cancelled
      /// to prevent sending out additional 'walking' events
      if (t != null) {
        t!.cancel();

        /// If a previous status was either not set yet, or was 'stopped'
        /// then a 'walking' event should be emitted.
        if (pedestrianStatus == null || pedestrianStatus == Constant.stopped) {
          _androidPedestrianController.add(PedestrianStatus.fromEvent(Constant.walking));
          pedestrianStatus = Constant.walking;
        }
      }

      /// After receiving an event, start a timer for 2 seconds, after
      /// which a 'stopped' event is emitted. If it manages to go through,
      /// it is because no events were received for the 2 second duration
      t = Timer(Duration(seconds: 2), () {
        _androidPedestrianController.add(PedestrianStatus.fromEvent(Constant.stopped));
        pedestrianStatus = Constant.stopped;
      });
    });

    return _androidPedestrianController.stream;
  }


  /// Returns the steps taken since last system boot.
  /// Events may come with a delay.
  @override
  Stream<StepCount> get stepCountStream => _stepCountChannel
      .receiveBroadcastStream()
      .map((event) => StepCount.fromEvent(event));

}
